/*
 * reference https://github.com/reactjs/redux/blob/master/examples/real-world/src/middleware/api.js
 * */

import config                       from '../config';
import {CALL_API}                   from '../constants';

import {BASE_URL} from '../config/index'
// This makes every API response have the same shape, regardless of how nested it was.
const callApi = ({url, base = BASE_URL, options}) => {

    const req = new Request(`${base}/${url}`, Object.assign({}, options));

    return fetch(req)
        .then(response => response.json().then(json => {
            if (!response.ok) {
                return Promise.reject(json)
            }
            return json;
        }));

};

// A Redux middleware that interprets actions with CALL_API info specified.
// Performs the call and promises when such actions are dispatched.
export default store => next => action => {

    const callAPI = action[CALL_API];
    if (typeof callAPI === 'undefined') {
        return next(action);
    }

    //check
    if(process.env.NODE_ENV !== 'production'){
        var {types, url} = callAPI;
        if (typeof url !== 'string') {
            throw new Error('Specify a string url.');
        }
        if (!Array.isArray(types) || types.length !== 3) {
            throw new Error('Expected an array of three action types.');
        }
        if (!types.every(type => typeof type === 'string')) {
            throw new Error('Expected action types to be strings.');
        }
    }

    const actionWith = data => {
        const finalAction = Object.assign({}, action, data);
        delete finalAction[CALL_API];
        return finalAction;
    };

    const [requestType, successType, failureType] = callAPI.types;

    const errorType = error => next(actionWith({
        type: failureType,
        error: `${error.message}`,
        success: false,
    }));

    // next(actionWith({type: requestType}));

    return callApi(callAPI).then(
        response => {
            var {errorStatus = r => r.code === '200', hideError} = callAPI;
            if(errorStatus(response)){
                callAPI.extra && callAPI.extra(response);
                next(actionWith({response, type: successType}));
                return response.data;
            }
            !hideError && errorType({message: `${response.code}:${response.message}`});
            return Promise.reject('internal');
        },
        err => {
            errorType(err);
            return Promise.reject('http');
        }
    );

};
